use std::cell::{RefCell, RefMut};
use std::rc::Rc;

use crate::instruction::instruction::Instruction;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::{VMValEnum, VMValInteger, VMValLong};

pub struct ladd {}

impl Instruction for ladd {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let v1 = frame.borrow().pop_long_from_stack();
        let v2 = frame.borrow().pop_long_from_stack();
        frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValLong {
            val: VMValLong {
                num: v1.num + v2.num
            }
        });
    }

    fn to_string(&self) -> String {
        String::from("ladd")
    }
}


pub struct iadd {}

impl Instruction for iadd {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let ro_frame = frame.borrow();
        let mut rw_operand_stack = ro_frame.operand_stack.borrow_mut();
        let v1 = {
            let val_enum = rw_operand_stack.pop().unwrap();
            VMValEnum::convert2integer(&val_enum)
        };
        let v2 = {
            let val_enum = rw_operand_stack.pop().unwrap();
            VMValEnum::convert2integer(&val_enum)
        };
        rw_operand_stack.push(VMValEnum::VMValInteger {
            val: VMValInteger {
                num: v1.num + v2.num
            }
        });
    }

    fn to_string(&self) -> String {
        String::from("iadd")
    }
}